#include "Parser.h"
#include "Kernels.h"
#include "Chronometer.h"
#include <iomanip>

int main(int argc, char *argv[])
{
    Chronometer c;

#ifdef _CUDA
    if(argc != 4)
    {
        cerr << "Usage mode: " << argv[0] << " <dictionary's filename> <number of blocks> <number os threads>" << endl;
        return EXIT_FAILURE;
    }

    uint blocks = atoi(argv[2]);
    uint threads = atoi(argv[3]);
#else
    if(argc != 2)
    {
        cerr << "Usage mode: " << argv[0] << " <dictionary's filename>" << endl;
        return EXIT_FAILURE;
    }
#endif

    cout << "Reading dictionary" << endl;

    // Parser file and add words to dictionary
    Parser parser(argv[1]);
    Dictionary dict = parser.parse();

    // Aloca um vetor contendo o dicionário de palavras
    HostWordPair hostDict;
    dict.fill(hostDict);

    cout << "There is " << dict.count << " words in the dictionary" << endl;

    // Calcula as probabilidades acumuladas
    HostProb hostProb(_WD_SIZE + 1);

#ifdef _CUDA

    getWordProb(hostProb, CUDA_RAND_MAX);

    cout << "Setting up GPU" << endl;

	// Copia as variáveis necessárias para o dispositivo
	DevWordPair devDict = hostDict;
	DevProb devProv = hostProb;

	// Estados do CURAND
	HostState hostState(blocks * threads);
	DevState devState = hostState;

	// Inicializa os estados
    callSetupKernel(blocks, threads, devState);

    // Hits obtidos em cada iteração
    HostHits hostHits(1, 0);
    DevHits devHits = hostHits;

#else
    getWordProb(hostProb, RAND_MAX);
#endif

    uint hits = 0;
    uint step = 10;

    cout << "Random words generation started" << endl;

    while(hits < hostDict.size())
    {
        // Gera palavras aleatórias e as verifica no dicionário
#ifdef _CUDA
        hits = callCountHits(blocks, threads, devDict, devHits, devProv, devState);
#else
        hits = seqCountHits(hostDict, &hits, hostProb);
#endif

        if((hits * 100) / hostDict.size() >= step)
        {
            cout << "Progress: " << setw(3) << step << "% - Time elapsed: " << c.getSeconds() << " seconds" << endl;
            step += 10;
        }
    }

    return 0;
}
